package com.kmmlearn.findtime

import io.github.aakira.napier.Napier
import kotlinx.datetime.Clock
import kotlinx.datetime.Instant
import kotlinx.datetime.LocalDateTime
import kotlinx.datetime.TimeZone
import kotlinx.datetime.toInstant
import kotlinx.datetime.toLocalDateTime
import kotlin.math.abs

class TimeZoneHelperImpl: TimeZoneHelper {
    override fun getTimeZoneStrings(): List<String> {
        return TimeZone.availableZoneIds.sorted()
    }

    override fun currentTime(): String {
        val currentMoment: Instant = Clock.System.now()
        val dateTime: LocalDateTime = currentMoment.toLocalDateTime(TimeZone.currentSystemDefault())
        return formatDateTime(dateTime)
    }

    override fun currentTimeZone(): String {
        val currentTimeZone = TimeZone.currentSystemDefault()
        return currentTimeZone.toString()
    }

    override fun hoursFromTimeZone(otherTimeZoneId: String): Double {
        val currentTimeZone = TimeZone.currentSystemDefault()
        val currentUTCInstant = Clock.System.now()

        val otherTimeZone = TimeZone.of(otherTimeZoneId)

        val currentDateTime: LocalDateTime = currentUTCInstant.toLocalDateTime(currentTimeZone)
        val currentDateTimeForOtherTimeZone: LocalDateTime = currentUTCInstant.toLocalDateTime(otherTimeZone)
        // Return the absolute difference between the hours (shouldn’t be negative),
        // making sure the result is a double.
        return abs((currentDateTime.hour - currentDateTimeForOtherTimeZone.hour) * 1.0)
    }

    override fun getTime(timeZoneId: String): String {
        val timezone = TimeZone.of(timeZoneId)
        val currentMoment: Instant = Clock.System.now()
        val dateTime: LocalDateTime = currentMoment.toLocalDateTime(timezone)
        return formatDateTime(dateTime)
    }

    override fun getDate(timeZoneId: String): String {
        val timezone = TimeZone.of(timeZoneId)
        val currentMoment: Instant = Clock.System.now()
        val dateTime: LocalDateTime = currentMoment.toLocalDateTime(timezone)
        val dayOfWeekStr =
            dateTime.dayOfWeek.name.lowercase().replaceFirstChar { it -> it.uppercase() }
        val monthStr =
            dateTime.month.name.lowercase().replaceFirstChar { it -> it.uppercase() }
        val dayOfMonthStr = dateTime.date.dayOfMonth
        return "$dayOfWeekStr, $monthStr $dayOfMonthStr"
    }

    override fun search(
        startHour: Int,
        endHour: Int,
        timeZoneStrings: List<String>
    ): List<Int> {
        // mutableListOf用于创建可变列表
        val goodHours = mutableListOf<Int>()
        val timeRange = IntRange(maxOf(0, startHour), minOf(23, endHour))
        val currentTimeZone = TimeZone.currentSystemDefault()
        for (hour in timeRange) {
            var isGoodHour = false
            for (zone in timeZoneStrings) {
                val otherTimeZone = TimeZone.of(zone)
                if (otherTimeZone == currentTimeZone) continue
                if (!isValid(timeRange, hour, currentTimeZone, otherTimeZone)) {
                    Napier.d("Hour $hour is not valid for time range")
                    isGoodHour = false
                    break
                } else {
                    Napier.d("Hour $hour is valid for time range")
                    isGoodHour = true
                }
            }
            if (isGoodHour) {
                goodHours.add(hour)
            }
        }
        return goodHours
    }

    private fun isValid(
        timeRange: IntRange,
        hour: Int,
        currentTimeZone: TimeZone,
        otherTimeZone: TimeZone
    ): Boolean {
        if (hour !in timeRange) {
            return false
        }
        val currentUTCInstant: Instant = Clock.System.now()
        // 为了获取当前在另外一个时区的时间，用于构建新的时间(即使跨天也没问题)
        val currentOtherDateTime: LocalDateTime =
            currentUTCInstant.toLocalDateTime(otherTimeZone)
        // 获取目标小时在对应时区的时间
        val otherDateTimeWithHour =
            LocalDateTime(
                currentOtherDateTime.year,
                currentOtherDateTime.month,
                currentOtherDateTime.dayOfMonth,
                hour,
                0,
                0,
                0
            )
        // 将时间转换为当前时区
        val localInstant: Instant = otherDateTimeWithHour.toInstant(currentTimeZone)
        // 将目标时区的目标时间（hour）转换为当前时区的时间，并检测是否在时间范围内
        val convertedTime = localInstant.toLocalDateTime(currentTimeZone)
        Napier.d("Hour $hour in Time Range ${otherTimeZone.id} is ${convertedTime.hour}" )
        return convertedTime.hour in timeRange
    }


    fun formatDateTime(dateTime: LocalDateTime): String {
        val stringBuilder = StringBuilder()
        var hour = dateTime.hour
        var minute = dateTime.minute
        var amPm = " AM"
        if (hour > 12) {
            amPm = " PM"
            hour -= 12
        }
        stringBuilder.append(hour.toString())
        stringBuilder.append(":")
        stringBuilder.append(if (minute < 10) "0" else "")
        stringBuilder.append(minute.toString())
        stringBuilder.append(amPm)
        return stringBuilder.toString()
    }

}